package battleship.data;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import battleship.Loop;
import battleship.Setup;
import battleship.field.Field;

public class SaveXML {

	public static final String[] PLAYERELEMENTNAMES =
		new String[] {"player1", "player2"};
	
	public static final String[] BOATNAMES =
		new String[] {
			"mijnenveger",
			"onderzeeer",
			"kruiser",
			"slagschip",
			"vliegdekschip"
	};
	
	public static final File FILE = new File("save/save.xml");
	private Document doc;
	private DocumentBuilder db;
	
	/**
	 * creates new DOM tree
	 * @throws ParserConfigurationException shouldn't get thrown
	 * @throws IOException when a new file could not be created if required
	 */
	public SaveXML() throws ParserConfigurationException, IOException
	{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		this.db = dbf.newDocumentBuilder();
		doc = db.newDocument();
		
		if(!FILE.exists())
		{
			FILE.createNewFile();
		}
	}
	
	/**
	 * retrieves data from the game
	 */
	public void update()
	{
		// deletion of previous dom elements
		doc = db.newDocument();
		
		/*
		 * Standard elements, not specific to the player
		 */
		
		//root
		Element root = doc.createElement("SaveFile");
		doc.appendChild(root);
		//root >
		Element turns = doc.createElement("turns");
		turns.setTextContent(String.valueOf(Loop.getTurns()));
		root.appendChild(turns);
		//root >
		Element field = doc.createElement("field");
		root.appendChild(field);
		//root > field > 
		Element f_width = doc.createElement("width");
		f_width.setTextContent(String.valueOf(Field.getWidth()));
		field.appendChild(f_width);
		//root > field >
		Element f_height = doc.createElement("height");
		f_height.setTextContent(String.valueOf(Field.getHeight()));
		field.appendChild(f_height);
		//root >
		Element players = doc.createElement("players");
		root.appendChild(players);
		
		// player dependent information
		for(int player = 0; player < Setup.getPlayers().length; ++player)
		{

			
			
			//root > players >
			Element playerEl = doc.createElement(PLAYERELEMENTNAMES[player]); //player1/2
			root.appendChild(playerEl);
			//root > players > player1 >
			Element playerElname = doc.createElement("name");
			playerElname.setTextContent(Setup.getPlayers()[player].getName());
			playerEl.appendChild(playerElname);
			//root > players > player1 >
			Element playerElbot = doc.createElement("isBot");
			playerElbot.setTextContent(Setup.getPlayers()[player].isBot()?"true":"false");
			playerEl.appendChild(playerElbot);
			//root > players > player1 >
			Element playerElboats = doc.createElement("boats");
			playerEl.appendChild(playerElboats);
			//root > players > player1 > boats
			
			StringBuilder attackstring = new StringBuilder();
			
			boolean fieldHits[][] = Setup.getPlayers()[player].getField().getField();
			
			for(int row = 0; row < fieldHits.length; ++row)
			{
				for(int column = 0; column < fieldHits[row].length; ++column)
				{
					attackstring.append(fieldHits[row][column]?1:0);
				}
				attackstring.append(", ");
			}
			Element attacksEl = doc.createElement("hits");
			attacksEl.setTextContent(attackstring.toString());
			playerEl.appendChild(attacksEl);
			
			for(int boat = 0; boat < Setup.getPlayers()[player].getField().getBoats().length; ++boat)
			{
				Element playerElboat = doc.createElement(BOATNAMES[boat]);
				
				playerElboat.setTextContent(Setup.getPlayers()[player].getField().getBoats()[boat].toString());
				playerElboats.appendChild(playerElboat);
			}

		}
		
	}
	
	/**
	 * writes the current DOM tree to the save file
	 * @throws TransformerException when the output is not available
	 */
	public void transform() throws TransformerException
	{
		TransformerFactory tff = TransformerFactory.newInstance();
		tff.setAttribute("indent-number", 4);
		Transformer trans = tff.newTransformer();
		trans.setOutputProperty(OutputKeys.INDENT, "yes");
		
		DOMSource src = new DOMSource(doc);
		StreamResult result = new StreamResult(FILE);
		
		trans.transform(src, result);
	}
	
}
